package com.lemon.cloud.admin.web;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Sets;
import com.lemon.cloud.admin.dto.MenuDTO;
import com.lemon.cloud.admin.service.SysMenuService;
import com.lemon.cloud.admin.service.SysRoleService;
import com.lemon.cloud.admin.vo.AppMenuVO;
import com.lemon.cloud.comm.constants.OAuth2Constant;
import com.lemon.cloud.comm.constants.enums.LogBusType;
import com.lemon.cloud.comm.model.ResultMsg;
import com.lemon.cloud.comm.po.SysMenu;
import com.lemon.cloud.comm.po.SysRole;
import com.lemon.cloud.comm.po.SysUser;
import com.lemon.cloud.log.annotation.SysLog;
import com.lemon.cloud.security.model.SecurityUser;
import com.lemon.cloud.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("menu")
@Tag(name = "菜单接口")
public class SysMenuController {

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysRoleService roleService;

    /**
     * 返回当前用户的树形菜单集合
     *
     * @param parentId 父节点ID
     * @return 当前用户的树形菜单
     */
    @Operation(
            summary = "返回当前用户的树形菜单集合",
            parameters = {
                    @Parameter(name = OAuth2Constant.APP_ID_HEAD, description = "app_id，平台管理为-1", required = false, in = ParameterIn.HEADER),
                    @Parameter(name = "parentId", description = "父级id，平台管理为-1", required = false, in = ParameterIn.QUERY),
                    @Parameter(name = "type", description = "类型默认是left，可用值：left、top、button", required = false, in = ParameterIn.QUERY),
            }
    )
    @GetMapping
    public ResultMsg<List<Tree<Long>>> getUserMenu(@RequestParam(value = "parentId",required = false) Long parentId,
                                                   @RequestParam(value = "type",required = false) String type,
                                                   @RequestHeader(value = OAuth2Constant.APP_ID_HEAD, required = false) Long appId
    ) {

        // 获取符合条件的菜单
        SecurityUser user = SecurityUtils.getUser();
        SysUser sysUser = user.getSysUser();
        List<SysRole> roleList = roleService.getRolesByUserId(sysUser.getId());
        Set<SysMenu> menuSet = Sets.newHashSet();
        for (SysRole r : roleList) {
            menuSet.addAll(r.getPermissionList());
        }
        return ResultMsg.resultSuccess(sysMenuService.filterMenu(menuSet, type, parentId, appId));
    }

    /**
     * 返回树形菜单集合
     *
     * @param lazy     是否是懒加载
     * @param parentId 父节点ID
     * @return 树形菜单
     */
    @Operation(
            summary = "返回树形菜单集合",
            parameters = {
                    @Parameter(name = "lazy", description = "是否懒加载", required = false, in = ParameterIn.QUERY),
                    @Parameter(name = "parentId", description = "父级id，（基础平台为-1）", required = false, in = ParameterIn.QUERY),
                    @Parameter(name = "appId", description = "平台id，（平台id为-1）", required = false, in = ParameterIn.QUERY),
            }
    )
    @GetMapping(value = "/tree")
    public ResultMsg<List<Tree<Long>>> getTree(boolean lazy, Long parentId, Long appId) {
        return ResultMsg.resultSuccess(sysMenuService.treeMenu(lazy, parentId,appId));
    }

    /**
     * 返回角色的菜单集合
     *
     * @param roleId 角色ID
     * @return 属性集合
     */
    @Operation(
            summary = "返回角色的菜单集合",
            parameters = {
                    @Parameter(name = "roleId", description = "角色ID", required = true, in = ParameterIn.PATH),
            },
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = List.class))}, useReturnTypeSchema = true)
            }
    )
    @GetMapping("/tree/{roleId}")
    public ResultMsg<List<AppMenuVO>> getRoleTree(@PathVariable("roleId") Long roleId) {
        return ResultMsg.resultSuccess(sysMenuService.findMenuByRoleId(roleId));
    }

    @Operation(
            summary = "详情",
            parameters = {
                    @Parameter(name = "id", description = "菜单ID", required = true, in = ParameterIn.PATH),
            }
    )
    @GetMapping("/{id:\\d+}")
    public ResultMsg<SysMenu> getById(@PathVariable("id") Long id) {
        return ResultMsg.resultSuccess(sysMenuService.getById(id));
    }

    /**
     * 新增菜单
     */
    @Operation(
            summary = "新增菜单",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SysMenu.class))}, useReturnTypeSchema = true)
            }
    )
    @SysLog(value = "新增菜单", businessType = LogBusType.ADD)
    @PostMapping
    @PreAuthorize("hasAnyAuthority('sys_menu_add')")
    public ResultMsg<SysMenu> addMenu(@Parameter @Valid @RequestBody MenuDTO menuDTO) {
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(menuDTO, sysMenu);
        if (ObjectUtil.isNull(sysMenu.getAppId())) {
            sysMenu.setAppId(getParentAppId(sysMenu.getParentId()));
        }
        sysMenu.setId(IdWorker.getId());
        sysMenu.setCreateTime(LocalDateTime.now());
        sysMenu.setUpdateTime(LocalDateTime.now());
        sysMenu.setCreateBy(SecurityUtils.getUser().getUsername());
        sysMenu.setUpdateBy(SecurityUtils.getUser().getUsername());
        if (!validPermission(menuDTO.getPermission())) {
            return ResultMsg.resultFail("权限表示不能以ROLE_开头");
        }
        sysMenuService.save(sysMenu);
        return ResultMsg.resultSuccess(sysMenu);
    }

    @Operation(
            summary = "删除菜单",
            parameters = @Parameter(name = "id", description = "菜单id", in = ParameterIn.PATH, required = true),
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "删除菜单", businessType = LogBusType.DELETE)
    @DeleteMapping("/{id:\\d+}")
    @PreAuthorize("hasAnyAuthority('sys_menu_del')")
    public ResultMsg<Boolean> removeById(@PathVariable("id") Long id) {
        return sysMenuService.removeMenuById(id);
    }

    /**
     * 更新菜单
     *
     * @param menuDTO
     * @return
     */
    @Operation(
            summary = "更新菜单",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "更新菜单", businessType = LogBusType.MODIFY)
    @PutMapping
    @PreAuthorize("hasAnyAuthority('sys_menu_edit')")
    public ResultMsg<Boolean> update(@Parameter @Valid @RequestBody MenuDTO menuDTO) {
        SysMenu sysMenu = new SysMenu();
        if (menuDTO.getId().equals(menuDTO.getParentId())) {
            return ResultMsg.resultFail("父级菜单不能为自己");
        }
        BeanUtils.copyProperties(menuDTO, sysMenu);
        if (ObjectUtil.isNull(sysMenu.getAppId())) {
            sysMenu.setAppId(getParentAppId(sysMenu.getParentId()));
        }
        sysMenu.setUpdateTime(LocalDateTime.now());
        sysMenu.setUpdateBy(SecurityUtils.getUser().getUsername());
        if (!validPermission(menuDTO.getPermission())) {
            return ResultMsg.resultFail("权限表示不能以ROLE_开头");
        }
        return ResultMsg.resultSuccess(sysMenuService.updateMenuById(sysMenu));
    }

    private boolean validPermission(String permission) {
        if (StrUtil.isEmpty(permission)) {
            return true;
        }
        return !permission.startsWith(OAuth2Constant.ROLE_PREFIX);
    }

    private Long getParentAppId(Long parentId) {
        SysMenu parent = sysMenuService.getById(parentId);
        if (parent == null) {
            throw new IllegalArgumentException("父级菜单不存在，请刷新页面");
        }
        return parent.getAppId();
    }
}
